package com.ihr360.rest.projector;

import com.ihr360.rest.core.Ihr360ProjectionDefinitions;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

public class EntityProjector  implements Projector  {
    private final Ihr360ProjectionDefinitions definitions;
    private final ProjectionFactory factory;
    private final String projection;

    public EntityProjector(Ihr360ProjectionDefinitions definitions, ProjectionFactory factory, String projection) {
        this.definitions = definitions;
        this.factory = factory;
        this.projection = projection;
    }

    @Override
    public Object project(Object source) {

        return projectWithDefault(source, new Converter<Object, Object>() {

            @Override
            public Object convert(Object source) {
                return source;
            }
        });
    }
    /**
     * Creates the projection for the given source instance falling back to the given {@link Converter} if no explicit
     * projection is selected.
     *
     * @param source must not be {@literal null}.
     * @param converter must not be {@literal null}.
     * @return
     */
    private Object projectWithDefault(Object source, Converter<Object, Object> converter) {

        Assert.notNull(source, "Projection source must not be null!");
        Assert.notNull(converter, "Converter must not be null!");

        if (!StringUtils.hasText(projection)) {
            return converter.convert(source);
        }

        Class<?> projectionType = definitions.getProjectionType(source.getClass(), projection);
        return projectionType == null ? converter.convert(source) : factory.createProjection(projectionType, source);
    }
}